﻿<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>Slide Show</title>
    <meta name="author" content="333pei@gmail.com" />
    <meta name="license" content="BSD" />
    <style type="text/css">
        .clearfix:before,.clearfix:after{content:".";display:block;height:0;overflow:hidden}.clearfix:after{clear:both}.clearfix{zoom:1}
        #sliding *
        {
            margin: 0;
            padding: 0;
        }
        .slide
        {
            line-height: 200px;
            width: 300px;
            text-align: center;
            vertical-align: middle;
            border: 1px dotted red;
            display: block;            
            display:inline-block;
            _display:inline;
            _zoom:1;            
        }
        
        #container
        {
            white-space: nowrap;
            height: 200px;
            border: 1px solid blue;
            padding: 0;
            margin: 0;
            position: absolute;
            top: 0px;
            
        }
        
        #mask 
        {
            width:560px;
            overflow:hidden;
        }
        
        #viewer
        {
            margin-left: 130px;
            width: 300px;
            height: 200px;
            border: 1px solid yellow;
            position: relative;
        }
        
        #sliding .slide-button
        {
            width: 10px;
            height: 10px;
            border-radius: 5px;
            background-color: Gray;
            display: block;
            float: left;
            cursor: pointer;
            margin-left: 4px;
            margin-right: 4px;
            text-indent: -2000px;
        }
        
        #sliding .slide-button.selected 
        {
            border-radius: 0px;
        }
        
        #buttoncontainer
        {
            margin-top: 10px;
            text-align: center;
        }
        
        #arrows a 
        {
            margin-left: 20px;
            margin-right: 20px;
            cursor: pointer;
        }
    </style>
    <script type="text/javascript" src="yui-min.js"></script>
</head>
<body>
    <div id="sliding">
        <div id="mask">
            <div id="viewer">
                <div id="container">
                    <div class="slide selected" style="background-color:#aaa">
                        1<span>a</span>
                    </div><div class="slide" style="background-color:#888">
                        2
                    </div><div class="slide" style="background-color:#666">
                        3
                    </div><div class="slide">
                        4
                    </div><div class="slide">
                        5
                    </div><div class="slide">
                        6
                    </div><div class="slide">
                        7
                    </div><div class="slide">
                        8
                    </div><div class="slide">
                        9
                    </div><div class="slide">
                        10
                    </div>
                </div>
            </div>
        </div>
        <div id="buttoncontainer">
        </div>
        <div id="arrows">
            <a id="leftonebutton">left</a> <a id="rightonebutton">right</a> <a id="togglesliding">stop</a>
        </div>
    </div>
    <script type="text/javascript">
        function autosilder(Y, viewerid, containerid, navcontainerid, rightoneid, leftoneid, globalDuration) {
            var viewer = Y.one("#" + viewerid);
            var container = Y.one("#" + containerid);
            var slides = Y.all("#" + containerid + ">*");
            var count = slides.size();
            if (count < 5) {
                alert("the number of slide blocks must be equal or greater than 5.");
                return;
            }
            var buttons = [];

            var curNode = slides.item(0);
            function moveContainer(newleft, duration, continuous) {
                var left = parseInt(container.getStyle("left"));
                if (newleft == left) {
                    continuous();
                    return;
                }
                var unit = (newleft - left) / duration;
                container.setStyle("left", (left + unit) + "px");
                duration -= 1;
                var func = function () {
                    left = parseInt(container.getStyle("left"));
                    if (duration <= 0) {
                        if (left != newleft) {
                            container.setStyle("left", newleft + "px");
                        }
                        continuous();
                        return;
                    }
                    container.setStyle("left", (left + unit) + "px");
                    duration -= 1;
                    setTimeout(func, duration);
                };
                setTimeout(func, duration);
            }

            function countLeft(curNode) {
                var i = 0;
                var n = curNode.previous();
                while (n) {
                    i++;
                    n = n.previous();
                }
                return i;
            }

            function countRight(curNode) {
                var i = 0;
                var n = curNode.next();
                while (n) {
                    i++;
                    n = n.next();
                }
                return i;
            }

            function fixAtBegin() {
                container.setStyle("left", (container.getX() - viewer.getX()) + "px");
                container.setStyle("right", null);
            }

            function fixAtEnd() {
                container.setStyle("right", (-(container.get("region").width + container.getX()) + (viewer.get("region").width + viewer.getX())) + "px");
                container.setStyle("left", null);
            }

            function rearrangeAtBegin() {
                var p = curNode.next().next();
                var ary = [];
                while (p) {
                    ary.push(p);
                    p = p.next();
                }
                for (var i = 0; i < ary.length; i++) {
                    container.removeChild(ary[i]);
                }

                fixAtEnd();
                var firstnode;
                p = curNode;
                while (true) {
                    if (p.previous() == null) {
                        firstnode = p;
                        break;
                    }
                    p = p.previous();
                }
                p = ary.shift();
                while (p) {
                    container.insertBefore(p, firstnode);
                    p = ary.shift();
                }
                fixAtBegin();
            }

            function rearrangeAtEnd() {
                fixAtEnd();
                var p = curNode.previous().previous();
                var ary = [];
                while (p) {
                    ary.push(p);
                    p = p.previous();
                }
                for (var i = 0; i < ary.length; i++) {
                    container.removeChild(ary[i]);
                }
                fixAtBegin();
                p = ary.pop();
                while (p) {
                    container.appendChild(p);
                    p = ary.pop();
                }
            }

            function forEach(ary, func) {                
                for (var i = 0; i < ary.length; i++) {
                    func(ary[i], i);
                }
            }

            var indexChangedHandlers = [];
            function setCurrent(n) {
                if (curNode == n) return;
                var oldNode = curNode;
                buttons[curNode.__slideIndex].removeClass("selected");
                curNode = n;
                buttons[curNode.__slideIndex].addClass("selected");
                forEach(indexChangedHandlers, function (func) {
                    func(oldNode.__slideIndex, curNode.__slideIndex);
                });            
            }

            var working = false;
            function rightOne(duration, continuous) {
                var nextNode = curNode.next();
                var newleft = parseInt(container.getStyle("left")) + curNode.getX() - nextNode.getX();
                function func() {
                    setCurrent(nextNode);                    
                    continuous();
                }
                if (countRight(curNode) <= 2) {
                    moveContainer(newleft, duration, function () {
                        rearrangeAtEnd();
                        func();
                    });
                    return true;
                }
                moveContainer(newleft, duration, func);
                return true;
            }

            function leftOne(duration, continuous) {
                var previousNode = curNode.previous();
                var newleft = parseInt(container.getStyle("left")) + curNode.getX() - previousNode.getX();
                function func() {
                    setCurrent(previousNode);                    
                    continuous();
                }
                if (countLeft(curNode) <= 2) {
                    moveContainer(newleft, duration, function () {
                        rearrangeAtBegin();
                        func();
                    });
                    return true;
                }
                moveContainer(newleft, duration, func);
                return true;
            }

            function donothing() { };

            var autoslide = null;
            var lastCommand = null;
            var runningStatusChangedHandlers = [];

            function fireRunningStatusChanged() {
                for (var i = 0; i < runningStatusChangedHandlers.length; i++) {
                    runningStatusChangedHandlers[i](autoslide != null);
                }
            }

            function genericComplete() {            
                while (lastCommand) {
                    var x = lastCommand;
                    lastCommand = null;
                    x();
                }
                working = false;            
            }

            function startAutoSlide(autoduration, slideduration) {
                if (autoslide) return;
                autoslide = setInterval(function () {
                    if (working) return;
                    working = true;
                    rightOne(slideduration, genericComplete);
                }, autoduration);
                fireRunningStatusChanged();
            }
            function stopAutoSlide() {
                if (!autoslide) return;
                clearInterval(autoslide);
                genericComplete();
                autoslide = null;
                fireRunningStatusChanged();
            }

            Y.one("#" + rightoneid).on("click", function (e) {
                if (working) {
                    lastCommand = function () {
                        stopAutoSlide();
                        rightOne(globalDuration, donothing);
                    };
                    return;
                }
                working = true;
                stopAutoSlide();
                return rightOne(globalDuration, genericComplete);
            });
            Y.one("#" + leftoneid).on("click", function (e) {
                if (working) {
                    lastCommand = function () {
                        stopAutoSlide();
                        leftOne(globalDuration, donothing);
                    };
                    return;
                }
                working = true;
                stopAutoSlide();
                return leftOne(globalDuration, genericComplete);
            });

            function slideTo(targetNode, duration, complete) {
                var distance = (targetNode.__slideIndex - curNode.__slideIndex);
                if (distance == 0) {
                    complete();
                    return true;
                }
                function iterate(x, func) {
                    if (targetNode == curNode) {
                        complete();
                        return true;
                    }

                    return func(x, function () {
                        iterate(x, func);
                    });
                }
                if (distance > 0) {
                    return iterate(duration / Math.abs(distance), rightOne);
                } else {
                    return iterate(duration / Math.abs(distance), leftOne);
                }
            }

            var buttoncontainer = Y.one("#" + navcontainerid);
            for (var i = 0; i < count; i++) {
                var bn = Y.Node.create("<a class='slide-button'>" + i + "</a>");
                bn.__slideIndex = i;
                slides.item(i).__slideIndex = i;
                buttons.push(bn);
                buttoncontainer.appendChild(bn);
                bn.on("click", function (e) {
                    var this_ = this;
                    if (working) {
                        lastCommand = function () {
                            stopAutoSlide();
                            slideTo(slides.item(this_.__slideIndex), globalDuration, donothing);
                        }
                        return;
                    }
                    working = true;

                    stopAutoSlide();
                    if (!slideTo(slides.item(this_.__slideIndex), globalDuration, genericComplete)) {
                        alert("!!!");
                    }
                });
            }
            buttons[0].addClass("selected");

            container.removeChild(slides.item(count - 1));
            container.removeChild(slides.item(count - 2));
            fixAtEnd();
            container.insertBefore(slides.item(count - 2), slides.item(0));
            container.insertBefore(slides.item(count - 1), slides.item(0));
            fixAtBegin();

            function removeElement(ary, elt) {
                for (var i = 0; i < elt.length; i++) {
                    if (elt == runningStatusChangedHandlers[i]) {
                        runningStatusChangedHandlers.splice(i, 1);
                        return true;
                    }
                }
                return false;
            }

            return {
                start: startAutoSlide,
                stop: stopAutoSlide,
                addOnRunningStatusChanged: function (handler) {
                    runningStatusChangedHandlers.push(handler);
                },
                addOnIndexChanged: function (handler) {
                    indexChangedHandlers.push(handler);
                },
                removeOnIndexChanged: function (handler) {
                    removeElement(indexChangedHandlers, handler);
                },
                removeOnRunningStatusChanged: function (handler) {
                    removeElement(runningStatusChangedHandlers, handler);
                },
                running: function () { return autoslide != null; }
            };
        }
        YUI().use("node", function (Y) {
            var slider = autosilder(Y, "viewer", "container", "buttoncontainer", "rightonebutton", "leftonebutton", 20);
            var runningStatusFunc = function (running) {
                if (running) {
                    Y.one("#togglesliding").setContent("stop");
                    return;
                }
                Y.one("#togglesliding").setContent("start");
            }

            slider.addOnRunningStatusChanged(runningStatusFunc);
            //slider.removeOnRunningStatusChanged(runningStatusFunc);
            //slider.addOnRunningStatusChanged(runningStatusFunc);
            slider.addOnIndexChanged(function (oldvalue, newvalue) {
                if (newvalue == 0 && oldvalue != newvalue) {
                    slider.stop();
                }
            });
            slider.start(1000, 20);
            Y.one("#togglesliding").on("click", function (e) {
                if (slider.running()) {
                    slider.stop();
                } else {
                    slider.start(1000, 20);
                }
            });
        });
    </script>
</body>
</html>
